package JVM.第02篇_类的加载篇;

/**
 *  1   有哪几种类加载器  如上
 *  2   双亲委派机制     （先从根加载器找）
 *         先从启动类加载器 （Bootstrap）->扩展类加载器（Extension)->
 *         应用程序类加载器 （AppClassLoader）
 *
 *         当一个类收到了类加载请求，他首先不会尝试自己去加载这个类，
 *         而是把这个"请求委派给父类去完成"，每一个层次类加载器都是如此，
 *         因此所有的加载请求都应该传送到启动类加载其中，
 *         只有当父类加载器反馈自己无法完成这个请求的时候
 *         (在它的加载路径下没有找到所需加载的Class)，
 *         子类加载器才会尝试自己去加载。
 *      采用双亲委派的一个好处是比如加载位于rt.jar包中的类java.lang.Object,
 *      不管是哪个加载器加载这个类，最终都是委托给顶层的启动类加载器进行加载，
 *      这样就保证了使用不同的类加载器最终得到的都是同样一个Object对象。
 *
 * 1.双亲委派机制优势
 * ●避免类的重复加载，确保一个类的全局唯一性
 * Java类随着它的类加载器一起具备了一种带有优先级的层次关系，
 * 通过这种层级关系可以避免类的重复加载，当父亲已经加载了该类时，
 * 就没有必要子ClassLoader再加载一次。保护程序安全，防止核心API被随意篡改
 * 2.双亲委托模式的弊端
 * 检查类是否加载的委托过程是单向的，这个方式虽然从结构上说比较清晰，
 * 使各个ClassLoader的职责非常明确，但是同时会带来“个问题，
 * 即顶层的ClassLoader无法访问底层的ClassLoader所加载的类。
 *
 * 通常情况下，启动类加载器中的类为系统核心类，包括一些重要的系统接口，
 * 而在应用类加载器中，为应用类。
 * 按照这种模式，应用类访问系统类白然是没有问题，但是系统类访问应用类就会出现问题。
 * 比如在系统类中提供了一个接口，该接口需要在应用类中得以实现，
 * 该接口还绑定一个工厂方法，用于创建该接口的实例，而接口和工厂方法都在启动类加载器中。
 * 这时，就会出现该工厂方法无法创建由应用类加载器加载的应用实例的问题。
 *
 *
 * 3.结论:
 * 由于Java虚拟机规范并没有明确要求类加载器的加载机制一-定要使用双亲委派模型，
 * 只是建议采用这种方式而已.
 * 比如在Tomcat中，类加载器所采用的加载机制就和传统的双亲委派模型有一定区别，
 * 当缺省的类加载器接收到一个类的加载任务时，首先会由它自行加载，
 * 当它加载失败时，才会将类的加载任务委派给它的超类加载器去执行，
 * 这同时也是Servlet规范推荐的一种做法。
 *
 *
 */
public class C10_相关机制之双亲委派机制 {
    public static void main(String[] args) {
        //        sun.misc.Launcher//JVM的入口
        Object object =new Object();
        //System.out.println(object.getClass().getClassLoader().getParent().getParent());
        //System.out.println(object.getClass().getClassLoader().getParent());//Bootstrap  没有更上一级的加载器了 会报错
        System.out.println(object.getClass().getClassLoader());//Bootstrap 根加载器 无（由于Bootstrap是c++   所以为null）

        C10_相关机制之双亲委派机制 jvm=new C10_相关机制之双亲委派机制();
        System.out.println(jvm.getClass() == C10_相关机制之双亲委派机制.class);//true

        System.out.println(jvm.getClass().getClassLoader().getParent().getParent());//jvm的上上一个装载
        System.out.println(jvm.getClass().getClassLoader().getParent());//jvm的上一个装载器
        System.out.println(jvm.getClass().getClassLoader());//jvm是谁装载的

    }
}
